/*============================================================================
 * Copyright 2009 VMware Inc.
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
 * use this file except in compliance with the License. You may obtain a copy 
 * of the License at: http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
 * License for the specific language governing permissions and limitations 
 * under the License.
 ============================================================================*/

package com.vmware.vcloud.data;

import java.io.IOException;
import java.io.StringWriter;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

/**
 * @author Steve Jin (sjin@vmware.com)
 */

public class XmlBuilder 
{

	public static String buildVAppRenameReq(String vAppURL, String newName, String status, String size)
	{
		Document doc = DocumentHelper.createDocument();
	    Element root = doc.addElement("VApp");
	    root.addAttribute("href", vAppURL);
	    
	    root.addAttribute("type", VCloudConstants.TYPE_VAPP);
	    root.addAttribute("name", newName);
	    root.addAttribute("status", status);
	    root.addAttribute("size", size);
	    root.add(VCloudNameSpaces.VCLOUD);
	    root.add(VCloudNameSpaces.XSI);
	    root.add(VCloudNameSpaces.XSD);
	    return toString(doc);
	}
	
	public static String buildAddInternetServiceReq(String name, String protocol,	int port, String description) 
	{
		String reqBody = 
			"<InternetService xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns=\"urn:tmrk:vCloudExpress-1.0:request:createInternetService\">" 
			+ "<Name>NAME</Name><Protocol>PROTOCOL</Protocol><Port>PORT</Port><Enabled>true</Enabled>"
			+ "<Description>DESCRIPTION</Description></InternetService>";
			
		reqBody = reqBody.replaceAll("NAME", name);
		reqBody = reqBody.replaceAll("PROTOCOL", protocol);
		reqBody = reqBody.replaceAll("PORT", Integer.toString(port));
		reqBody = reqBody.replaceAll("DESCRIPTION", description);
		return reqBody;
	}
	
	public static String buildAddNodeReq(String privateIp, String name, int port, String description) 
	{
		String reqBody = 
			"<NodeService  xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns=\"urn:tmrk:vCloudExpress-1.0:request:createNodeService\">"
			+ "<IpAddress>IP</IpAddress><Name>NAME</Name><Port>PORT</Port><Enabled>true</Enabled><Description>DESCRIPTION</Description></NodeService>";
		
		reqBody = reqBody.replaceAll("DESCRIPTION", description); //call it before replacing IP as D*N has IP
		reqBody = reqBody.replaceAll("IP", privateIp);
		reqBody = reqBody.replaceAll("NAME", name);
		reqBody = reqBody.replaceAll("PORT", Integer.toString(port));
		
		return reqBody;
	}
	
	public static String buildVAppTempateParams(String vAppTemplateStr, String vAppName, Map<String, String> productProps
			, VirtualHardwareSection vHardware, String networkURL) throws IOException
	{
		 Document document = DocumentHelper.createDocument();
	     Element root = document.addElement("InstantiateVAppTemplateParams");
	     root.addAttribute("name", vAppName);
	     root.addAttribute("xml:lang", "en");
	     root.add(VCloudNameSpaces.VCLOUD);
	     root.add(VCloudNameSpaces.XSI);
	     
	     //Element vAppTemplate = 
	    	 root.addElement("VAppTemplate").addAttribute("href", vAppTemplateStr);
	     
	     Element instantiationParams = root.addElement("InstantiationParams");
	     
	     Element productSection = instantiationParams.addElement("ProductSection");
	     productSection.add(VCloudNameSpaces.OVF);
	     productSection.add(VCloudNameSpaces.Q1);

    	 QName ovfKey = new QName("key", VCloudNameSpaces.OVF);
    	 QName ovfVal = new QName("value", VCloudNameSpaces.OVF);
	     for(String key : productProps.keySet())
	     {
	    	 String val = productProps.get(key);
		     productSection.addElement("Property")
		     	.addAttribute(ovfKey, key)
		     	.addAttribute(ovfVal, val)
		     	.add(new Namespace("", "http://schemas.dmtf.org/ovf/envelope/1"));
	     }
	     
	     createVirtualHardwareSection(instantiationParams, vHardware);
   
	     //Element networkConfigSection = 
	    	 instantiationParams
	        .addElement("NetworkConfigSection")
	     	.addElement("NetworkConfig")
	     	.addElement("NetworkAssociation")
	     	.addAttribute("href", networkURL);
	     
	     OutputFormat format = OutputFormat.createPrettyPrint();
	     format.setExpandEmptyElements(false);
	     format.setSuppressDeclaration(true);
	     StringWriter sw = new StringWriter();
	     XMLWriter writer = new XMLWriter( sw, format );
	     writer.write( document );

	     return toString(document); 
	}

	private static String toString(Document doc)
	{
	     OutputFormat format = OutputFormat.createPrettyPrint();
	     format.setExpandEmptyElements(false);
	     format.setSuppressDeclaration(true);
	     StringWriter sw = new StringWriter();
	     XMLWriter writer = new XMLWriter( sw, format );
	     
	     try
	     {
	    	 writer.write( doc );
	     } catch (IOException ioe)
	     {
	    	 ioe.printStackTrace();
	     }
	     
	     String ret = sw.toString(); 
		 // patch a bug by dom4j in which empty namespaces are inserted
		 ret = ret.replaceAll("xmlns=\"\"", "");
	     
	     return ret;
	}
	
	private static void createVirtualHardwareSection(Element parent, VirtualHardwareSection vHardwareSection)
	{
	    Element virtualHardwareSection = parent.addElement("VirtualHardwareSection");
	    virtualHardwareSection.add(VCloudNameSpaces.Q1);
	    
	    createVirtualHardwareItem(virtualHardwareSection, vHardwareSection.vCPU);
	    createVirtualHardwareItem(virtualHardwareSection, vHardwareSection.vMem);
	}
	
	private static void createVirtualHardwareItem(Element parent, VirtualHardwareItem vhi)
	{
	    Element vhiElem = parent.addElement("Item");
	    vhiElem.add(new Namespace("", "http://schemas.dmtf.org/ovf/envelope/1"));
	    vhiElem.addElement("InstanceID")
	    	.addText(vhi.instanceID).add(VCloudNameSpaces.CIM);
	    vhiElem.addElement("ResourceType")
	    	.addText(vhi.resourceType).add(VCloudNameSpaces.CIM);
	    vhiElem.addElement("VirtualQuantity")
	    	.addText(vhi.virtualQuantity).add(VCloudNameSpaces.CIM);
	}
}
